package com.infnoon.ojback.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.infnoon.ojback.common.ErrorCode;
import com.infnoon.ojback.constant.CommonConstant;
import com.infnoon.ojback.exception.BusinessException;
import com.infnoon.ojback.exception.ThrowUtils;
import com.infnoon.ojback.mapper.ContestMapper;
import com.infnoon.ojback.model.dto.contest.ContestDoRequest;
import com.infnoon.ojback.model.dto.contest.ContestQueryRequest;
import com.infnoon.ojback.model.dto.contest.ContestRegisterRequest;
import com.infnoon.ojback.model.entity.Contest;
import com.infnoon.ojback.model.entity.Question;
import com.infnoon.ojback.model.entity.User;
import com.infnoon.ojback.model.vo.ContestVO;
import com.infnoon.ojback.model.vo.UserVO;
import com.infnoon.ojback.service.ContestService;
import com.infnoon.ojback.service.UserService;
import com.infnoon.ojback.utils.SqlUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
* @author 31124
* @description 针对表【contest(比赛)】的数据库操作Service实现
* @createDate 2025-01-06 20:23:46
*/
@Service
public class ContestServiceImpl extends ServiceImpl<ContestMapper, Contest>
    implements ContestService {

    @Resource
    private UserService userService;

    @Override
    public void validContest(Contest contest) {
        if (contest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        String contestName = contest.getContestName();
        String contestDescription = contest.getContestDescription();
        String contestTasks = contest.getContestTasks();
        Date registerStart = contest.getRegisterStart();
        Date registerEnd = contest.getRegisterEnd();
        Date contestStart = contest.getContestStart();
        Date contestEnd = contest.getContestEnd();

        ThrowUtils.throwIf(StringUtils.isAnyBlank(contestName, contestTasks), ErrorCode.PARAMS_ERROR);
        if (StringUtils.isNotBlank(contestDescription) && contestDescription.length() > 8192) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "比赛描述内容过长");
        }
        // 比赛报名 & 比赛 的开始与结束时间的差值 (分钟)
        long registerDiff = TimeUnit.MILLISECONDS.toMinutes(registerEnd.getTime() - registerStart.getTime());
        long contestDiff = TimeUnit.MILLISECONDS.toMinutes(contestEnd.getTime() - contestStart.getTime());
        if (registerDiff <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "比赛报名的截止时间不得早于开始时间");
        }
        if (contestDiff <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "比赛的截止时间不得早于开始时间");
        }

        Date now = new Date();
        // 比赛报名 & 比赛 的结束时间与当前时间的差值 (分钟)
        long registerDiffWithNow = TimeUnit.MILLISECONDS.toMinutes(now.getTime() - registerEnd.getTime());
        long contestDiffWithNow = TimeUnit.MILLISECONDS.toMinutes(now.getTime() - contestEnd.getTime());
        if (registerDiffWithNow <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "比赛报名的截止时间不得早于当前时间");
        }
        if (contestDiffWithNow <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "比赛的截止时间不得早于当前时间");
        }
    }

    @Override
    public QueryWrapper<Contest> getContestQueryWrapper(ContestQueryRequest contestQueryRequest) {
        QueryWrapper<Contest> queryWrapper = new QueryWrapper<>();
        if (contestQueryRequest == null) {
            return queryWrapper;
        }

        String contestName = contestQueryRequest.getContestName();
        Long userId = contestQueryRequest.getUserId();
        String sortField = contestQueryRequest.getSortField();
        String sortOrder = contestQueryRequest.getSortOrder();

        queryWrapper.like(StringUtils.isNotBlank(contestName), "contestName", contestName);
        queryWrapper.eq(ObjectUtils.isNotEmpty(userId), "userId", userId);
        queryWrapper.orderBy(SqlUtils.validSortField(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        return queryWrapper;
    }

    @Override
    public ContestVO getContestVO(Contest contest, HttpServletRequest request) {
        ContestVO contestVO = ContestVO.objToVo(contest);
        //  关联查询用户信息
        Long userId = contest.getUserId();
        User user = null;
        if (userId != null && userId > 0) {
            user = userService.getById(userId);
        }
        UserVO userVO = userService.getUserVO(user);
        contestVO.setUserVO(userVO);
        return contestVO;
    }

    @Override
    public Page<ContestVO> getContestVOPage(Page<Contest> contestPage, HttpServletRequest request) {
        List<Contest> contestList = contestPage.getRecords();
        Page<ContestVO> contestVOPage = new Page<>(contestPage.getCurrent(), contestPage.getSize(), contestPage.getTotal());
        if (CollUtil.isEmpty(contestList)) {
            return contestVOPage;
        }
        // 1. 关联查询用户信息
        Set<Long> userIdSet = contestList.stream().map(Contest::getUserId).collect(Collectors.toSet());
        Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
                .collect(Collectors.groupingBy(User::getId));

        // 填充信息
        List<ContestVO> contestVOList = contestList.stream().map(contest -> {
            ContestVO contestVO = ContestVO.objToVo(contest);
            Long userId = contest.getUserId();
            User user = null;
            if (userIdUserListMap.containsKey(userId)) {
                user = userIdUserListMap.get(userId).get(0);
            }
            contestVO.setUserVO(userService.getUserVO(user));
            return contestVO;
        }).collect(Collectors.toList());
        contestVOPage.setRecords(contestVOList);
        return contestVOPage;
    }

    @Override
    public void doContestRegister(ContestRegisterRequest contestRegisterRequest, User loginUser) {
        long userId = loginUser.getId();

        // 检查此用户是否已经报名
        List<Long> participants = contestRegisterRequest.getParticipants();
        if (participants.contains(userId)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "此用户已报名参加此比赛");
        }

        // 检查是否在有效报名时间内
        Date now = new Date();
        Date registerStart = contestRegisterRequest.getRegisterStart();
        Date registerEnd = contestRegisterRequest.getRegisterEnd();
        if (now.before(registerStart)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "比赛报名暂未开放");
        }
        if (now.after(registerEnd)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "比赛报名已截止");
        }

        // 将此用户加入报名名单
        participants.add(userId);
    }

    @Override
    public void doContest(ContestDoRequest contestDoRequest, User loginUser) {
        long userId = loginUser.getId();
        // 检查此用户是否已经报名
        List<Long> participants = contestDoRequest.getParticipants();
        if (!participants.contains(userId)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "此用户未报名参加此比赛");
        }

        // 检查是否在有效比赛时间内
        Date now = new Date();
        Date contestStart = contestDoRequest.getContestStart();
        Date contestEnd = contestDoRequest.getContestEnd();
        if (now.before(contestStart)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "比赛暂未开放");
        }
        if (now.after(contestEnd)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "比赛已截止");
        }
        Long id = contestDoRequest.getId();
        String contestName = contestDoRequest.getContestName();
        List<Question> contestTasks = contestDoRequest.getContestTasks();

        int current = contestDoRequest.getCurrent();
        int pageSize = contestDoRequest.getPageSize();
        String sortField = contestDoRequest.getSortField();
        String sortOrder = contestDoRequest.getSortOrder();
    }
}
